// LunchOMatic.cpp : Defines the entry point for the application.

#include "LunchOMatic.h"
#include <windows.h>
#include <aygshell.h>
#include <wincrypt.h>

static struct __LogoData
{
	int count;		// Number of logos present
	HBITMAP *logo;	// Array of logo bitmaps
} logos;

// The three indexes into the logos
// array for the currently selected
// resturants.
static int index1 = -1;
static int index2 = -1;
static int index3 = -1;

static void SeedRandomNumberGenerator()
{
	// Use the Cryptographic API to obtain a cryptographic
	// strength random number to use as the seed for our
	// random number generator.
	DWORD dwRandomSeed;
	HCRYPTPROV hCrypt;
	
	if (CryptAcquireContext(&hCrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
	{
		if (CryptGenRandom(hCrypt, sizeof(dwRandomSeed), (BYTE*)&dwRandomSeed))
		{
			srand(dwRandomSeed);
		}

		CryptReleaseContext(hCrypt, 0);
	}
}

static int GetRandomNumber(int minValue, int maxValue)
{
	// Now generate a random value within the
	// required range
	return minValue + (rand() % (maxValue - minValue));
}

static void Spin(HWND hDlg)
{
	// Select three adjacent restruants from our
	// list at random. Making sure to roll around
	// to the start of the list if we run off the
	// end.
	index1 = GetRandomNumber(0, logos.count);
    index2 = (index1 + 1) % logos.count;
    index3 = (index2 + 1) % logos.count;

	// Invalidate the dialog so that it gets
	// repainted (and hence the newly selected
	// restruants are displayed)
	InvalidateRect(hDlg, NULL, FALSE);
}

static int FindLogos()
{
	TCHAR szPath[MAX_PATH];
	WIN32_FIND_DATA fi;
	HANDLE hFind;

	// Display the wait cursor
	SetCursor(LoadCursor(NULL, IDC_WAIT));

	// Produce the search filter to search for
	// *.png files within the LunchLogos subdirectory
	GetModuleFileName(GetModuleHandle(NULL), szPath, MAX_PATH);
	wcscpy(wcsrchr(szPath, '\\') + 1, +_T("LunchLogos\\*.png"));

	// Allocate enough space to store 8 logos
	int maxLogos = 8;
	logos.count = 0;
	logos.logo = (HBITMAP *)malloc(sizeof(HBITMAP) * maxLogos);

	// Perform the actual search
	hFind = FindFirstFile(szPath, &fi);
	do
	{
		TCHAR szBuffer[MAX_PATH];

		// Convert the filename into a full path
		GetModuleFileName(GetModuleHandle(NULL), szBuffer, MAX_PATH);
		wcscpy(wcsrchr(szBuffer, '\\') + 1, +_T("LunchLogos\\"));
		wcscat(szBuffer, fi.cFileName);

		// If we've ran out of storage space, double
		// the size of our array, making sure not to loose
		// it's existing contents
		if (logos.count == maxLogos)
		{
			maxLogos *= 2;
			logos.logo = (HBITMAP *)realloc(logos.logo, sizeof(HBITMAP) * maxLogos);
		}

		// Load the current logo and add it to the
		// next available slot in the logo array
		logos.logo[logos.count++] = SHLoadImageFile(szBuffer);
	} while (FindNextFile(hFind, &fi));

	CloseHandle(hFind);

	// Return to the normal cursor (nothing on stylus
	// driven Windows Mobile).
	SetCursor(LoadCursor(NULL, IDC_ARROW));

	return logos.count;
}

static void Delay(int milliseconds)
{
	DWORD dwStart = GetTickCount();
	MSG msg;

	// While our delay period hasn't expired
	while ((GetTickCount() - dwStart) < milliseconds)
	{
		// Check if there are any messages in the
		// message queue
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			// And if there are deal with them
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
}

// Message handler for LunchOMatic dialog.
INT_PTR CALLBACK LunchOMaticDlg(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_INITDIALOG:
            {
                // Create a Done button and size it.  
                SHINITDLGINFO shidi;
				SHMENUBARINFO mbi;
                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
                shidi.hDlg = hDlg;
                SHInitDialog(&shidi);
				
				// Create a menu bar
				memset(&mbi, 0, sizeof(SHMENUBARINFO));
				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hDlg;
				mbi.nToolBarId = IDR_MENU;
				mbi.hInstRes   = GetModuleHandle(NULL);
				mbi.dwFlags = SHCMBF_HMENU;
				SHCreateMenuBar(&mbi);

				SeedRandomNumberGenerator();

				if (FindLogos() < 3)
				{
					// We don't have enough logos, so error out
					MessageBox(GetForegroundWindow(), _T("You must have atleast three logos in the LunchLogos directory for this application to work properly."), _T("Error"), MB_OK | MB_ICONERROR);
					SendMessage(hDlg, WM_CLOSE, 0, 0);
				}
				else
				{
					// Randomly select three restruants
					Spin(hDlg);
				}
            }
            return (INT_PTR)TRUE;

        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
			case IDOK:
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE;

			case IDC_SPIN:
				{
					HWND hWndMenuBar = SHFindMenuBar(hDlg);

					// Randomly decide how many times to spin
					int spinCount = GetRandomNumber(3, 6);

					SHEnableSoftkey(hWndMenuBar, IDC_SPIN, FALSE, FALSE);

					// Spin the correct number of times
					for (int i = 0; i < spinCount; i++)
					{
						Spin(hDlg);
						Delay(333);
					}

					SHEnableSoftkey(hWndMenuBar, IDC_SPIN, FALSE, TRUE);
				}
				return (INT_PTR)TRUE;
            }
            break;

        case WM_CLOSE:
            EndDialog(hDlg, message);
            return (INT_PTR)TRUE;

		case WM_CTLCOLORDLG:
			{
				// Paint the entire background of the window
				// with a light blue colour
				HBRUSH brush = CreateSolidBrush(RGB(173, 216, 230));
				return (INT_PTR)brush;
			}
			break;

		case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hdcDest = BeginPaint(hDlg, &ps);

				HDC hdcSrc = CreateCompatibleDC(hdcDest);

				HBRUSH hbrOld = (HBRUSH)SelectObject(hdcDest, GetStockObject(NULL_BRUSH));

				// Draw the arrow
				HBITMAP hbmpArrow = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_ARROW));
				SelectObject(hdcSrc, hbmpArrow);
				TransparentBlt(hdcDest, 130, 103, 107, 62, hdcSrc, 0, 0, 107,62, RGB(255,255,255));
				DeleteObject(hbmpArrow);

				// Draw the top logo
				if (index1 != -1)
				{
					int x = 38, y= 14, width=160, height=160;
					SelectObject(hdcSrc, logos.logo[index1]);
					StretchBlt(hdcDest, x, y, 50, 50, hdcSrc, 0, 0, width, height, SRCCOPY);
					Rectangle(hdcDest, x-1, y-1, x + 51, y + 51);
				}

				// Draw the middle logo
				if (index2 != -1)
				{
					int x = 13, y= 84, width=160, height=160;
					SelectObject(hdcSrc, logos.logo[index2]);
					StretchBlt(hdcDest, x, y, 100, 100, hdcSrc, 0, 0, width, height, SRCCOPY);
					Rectangle(hdcDest, x-1, y-1, x + 101, y + 101);
				}
				
				// Draw the bottom logo
				if (index3 != -1)
				{
					int x = 38, y= 204, width=160, height=160;
					SelectObject(hdcSrc, logos.logo[index3]);
					StretchBlt(hdcDest, x, y, 50, 50, hdcSrc, 0, 0, width, height, SRCCOPY);
					Rectangle(hdcDest, x-1, y-1, x + 51, y + 51);
				}

				SelectObject(hdcDest, hbrOld);

				DeleteDC(hdcSrc);

				EndPaint(hDlg, &ps);
			}
			break;

    }
    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	return DialogBox(hInstance, (LPCTSTR)IDD_LUNCHOMATIC, NULL, LunchOMaticDlg);
}